// topology.hpp: interHedFace for the topology class.
//
//////////////////////////////////////////////////////////////////////

#ifndef AM_SURFACE_TOPOLOGY
#define AM_SURFACE_TOPOLOGY

#include <vector>

#include "topology/blockalloc.h"

using namespace std;

class TopNode_;
class TopEdge_;
class TopElem_;
class TopBoundary;
class mshsurfIndexMap;
class topologyTree;

// cTopology
//////////////////////////////////////////////////////////////////////
class cTopology  
{
public:
           cTopology();
  virtual ~cTopology();
 
  void     Clear           (void);

  // main methods
  int      InsertMesh      (int n_node, int n_elem, double *coords, int *conn,
                            void (*func) (char *), bool invert_conn = false);
  void     BoundBox        (double min[3], double max[3]);
  void     UpdateNormals   (void);

  int      writeNF         (char *filename);
  int      readNF          (char *filename);
  int      WriteVTK        (char *filename);
  int      writeMatlab     (char *filename, char *open_type);

  // number of nodes, edges, bound edges, and elements
  int  NumNodes          (void) { return NumNode; };
  int  NumEdges          (void) { return NumEdge; };
  int  NumBoundEdges     (void) { return NumEdgeBound; };
  int  NumElems          (void) { return NumElem; };

  double getTolerance ( ) { return LocalTol; };

  // node information
  int     GetCoordNode      (int id, double coord[3]);
  void    SetCoordNode      (int id, double *new_coord);
  int     IsBoundaryNode    (int id);
  int     GetNormalNode     (int id, double normal[3]);
  void    SetPtsInative     (int id);
  int     IsActNode         (int id);
  int     ReturnNodeId      (double x, double y, double z);
  void    GetNodeVector     (double **node_vec);
  void    SetNodeInfo       (int id, int flag);
  void    SetNodeInfo       (int id, void *info);
  int     GetNodeInfo       (int id);
  void    GetNodeInfo       (int id, void **info);

  // edge information
  int     GetEdge           (int id, int *ei, int *ej);
  int     GetEdge           (int ei, int ej);
  int     GetEdgeSize       (int i, double mid[3], double *size);
  int     GetBoundEdge      (int i, int *ei, int *ej);
  int     GetBEdgeSize      (int i, double mid[3], double *size);
  int     GetIsEdgeValid    (int i);
  double  GetSmalestEdge    (void);
  int     getIdEdgeToNodes  (int i, int j);
  void    SetEdgeInfo       (int id, int flag);
  void    SetEdgeInfo       (int id, void *info);
  int     GetEdgeInfo       (int id);
  void    GetEdgeInfo       (int id, void **info);
  bool    IsBoundaryEdge    (int id);

  // element information
  int     GetElemNNodes     (int id); 
  int*    GetElemConn       (int id); 
  int     GetElemNorm       (int id, double normal[3]); 
  int     GetElemNormArea   (int id, double normal[3]); 
  int     GetElemIdEdge     (int id, int pos_adj); 
  int     GetIsElemValid    (int id);
  int     GetElemCenter     (int id, double center[3]);
  int     IsActElem         (int id);
  void    SetElemInfo       (int id, int flag);
  void    SetElemInfo       (int id, void *info);
  int     GetElemInfo       (int id);
  void    GetElemInfo       (int id, void **info);

  // loops
  int     GetNumLoops       (void);
  int     GetLoop           (int id, int *npts, int **idpts);

  // volume
  double  GetVolume ( );

  // adjacency information
  ///////////////////////////////////////////////////
  // node - nodes
  int     NumAdjNodeNode    (int id);
  void    AdjNodeNode       (int id, int *adj_nodes);
  int     OrientAdjNodeNode (int id, int *adj_nodes);
  // node - edges
  int     NumAdjEdgeToNode  (int id);
  int     AdjEdgeToNode     (int id, int pos);
  int     OppAdjEdgeToNode  (int id, int *ne, int **edges); // opposite adjacent edges to node
  int     OrientAdjEdgeToNode (int id, int *adj_edges);
  // node - elements
  int     AdjElemToNode     (int id, int *ne, int **elem);
  // edges - nodes
  int     AdjNodeToEdge     (int id, int *ei, int *ej);
  // edges - elements
  int     NumAdjElemToEdge  (int id);
  int     AdjElemToEdge     (int id, int pos);
  // elements - edges
  int     NumAdjEdgeToElem  (int id);
  int     AdjEdgeToElem     (int id, int pos);

   // edit
  bool   duplicateEdges     (int nedges, int *edges, bool inter_elem = false);

  bool   duplicateNodes     (int nnodes, int *nodes, bool inter_elem = false);

  // add elements
  bool   addElements        (int n_node, int n_elem, double *coords, int *conn,
                             void (*func) (char *), topologyTree *node_edge_tree,
                             bool invert_conn = false);

private:

  // node information
  int         NumNode;
  vector <TopNode_ *> NodeVector;

  // element information
  int         NumElem;
  vector <TopElem_ *> ElemVector;

  // edge information
  mshsurfIndexMap        *EdgeList;
  vector <TopBoundary *> BoundList;
  vector <TopEdge_ *>    EdgeVector;
  int                    NumEdge;
  vector <TopEdge_ *>    BoundVector;
  int                    NumEdgeBound;

  // boundbox
  double min[3], max[3];

  // surfaces
  int     NumSurfaces;

  double     LocalTol;    // local tolerance

  // blockalloc
  blockalloc <TopNode_> nodeBlock ;
  blockalloc <TopEdge_> edgeBlock ;
  blockalloc <TopElem_> elemBlock;

  // Feedback function
  void (*feedbackFunction) (char *);

  // methods
  int BuildEdgeList (void);

  int BuildAdjEdgesToNode (void);

  int BuildEdgesBoundary  (void);
  void RunAlongEdges (TopEdge_ *init_edge);

  void SetLocalToler (void);

  void IdentifySurfaces (void);
  void SetIdSurface     (int idSurf, TopElem_ *initElem);

  void SetValidFaces (void);

  void BuildOrientation (void);
  void OrientAdjElement (TopEdge_ *edge, int ciclo, TopElem_ **tail_elem);

  // mark nodes and edges to add new elements
  void markEdgesNodesWhenAddElems (cTopology *add_mesh, topologyTree *node_edge_tree,
                                   int *new_nodes);

  // duplicate node and update adjacencies
  void duplicateNode     (int node);
  void duplicateNode2Adj (int node);

  int getAdjEdgeNextNodeEdge (int node, int edge);


};

#endif
